package org.redrock.test.repository;

import com.google.gson.Gson;
import lombok.Data;
import org.redrock.test.bean.RequestInfo;
import org.redrock.test.config.WeixinConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.jdbc.core.*;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

@Repository
@EnableConfigurationProperties(value = {WeixinConfig.class})
public class AccessTokenRepository {

    @Autowired
    private WeixinConfig weixinConfig;
    @Autowired
    private NetworkRepository networkRepository;
    @Autowired
    private JdbcTemplate jdbcTemplate;

    final String apiFormat = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";

    public String getAccessToken() {
        String accessToken = this.getAccessTokenFromDatabase();
        if (StringUtils.isEmpty(accessToken)) {
            synchronized (this) {
                accessToken = this.getAccessTokenFromDatabase();
                if (StringUtils.isEmpty(accessToken)) {
                    String data = curlForNewAccessToken();
                    Gson gson = new Gson();
                    AccessToken at = gson.fromJson(data, AccessToken.class);
                    if (at != null) {
                        accessToken = at.getAccess_token();
                        this.saveAccessTokenInDatabase(accessToken);
                    } else {
                        Error error = gson.fromJson(data, Error.class);
                        //......
                    }
                }
            }
        }
        return accessToken;
    }

    private String getAccessTokenFromDatabase() {
        return jdbcTemplate.query(
                "call getAccessToken(?, ?)",
                preparedStatement -> {
                    int now = (int)(System.currentTimeMillis() / 1000);
                    String token = weixinConfig.getToken();
                    preparedStatement.setString(1, token);
                    preparedStatement.setInt(2, now);
                },
                resultSet -> {
                    return (resultSet.next() ? resultSet.getString("access_token") : null);
                }
        );
    }

    private void saveAccessTokenInDatabase(String accessToken) {
        jdbcTemplate.update(
                "call saveAccessToken(?, ?, ?)",
                preparedStatement -> {
                    String token = weixinConfig.getToken();
                    int now = (int)(System.currentTimeMillis() / 1000);
                    preparedStatement.setString(1, token);
                    preparedStatement.setInt(2, now);
                    preparedStatement.setString(3, accessToken);
                }
        );
    }

    private String curlForNewAccessToken() {
        String appId = weixinConfig.getAppId();
        String secret = weixinConfig.getSecret();
        String apiUrl = String.format(apiFormat, appId, secret);
        RequestInfo requestInfo = new RequestInfo(
                "get",
                apiUrl
        );
        return networkRepository.curl(requestInfo);
    }

    @Data
    private static class AccessToken {
        private String access_token;
        private int expires_in;
    }

    @Data
    private static class Error {
        private int errcode;
        private String errmsg;
    }
}
